//
//  ViewController.swift
//  GDSwift
//
//  Created by 热带雨林 on 2020/7/11.
//  Copyright © 2020 热带雨林. All rights reserved.
//

import UIKit

//  自己定义的类不需要到头文件, 但是使用第三方框架的时候需要导入

//class + { } 就是关于类的使用
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        //添加简单的视图
//        view1()
//        demo1()
//        demo2()
//        demo3()
//        demo4()
//        demo5()
//        demo6()
//        demo7()
//        demo8()
//        text1()
        
//        函数调用又返回值需要用变量接，之后打印
//        let result = text2(a: 1, b: 2)
//        print(result)
//        text4()
//        demo10()
//        demo11()
//        override()
        isKVC()
   
        
    }
    
    func isKVC(){
        /**
         Variable used within its own initial value
         说明是定义的对象与类名相同，给对象改个名字就好
         */
        
        let peo = people(dic: ["name":"zhangsan","age":"22","num":"28"])
        print(peo.name,peo.age)
        
    }
    
    //override
    func override(){
        
        //根据自定义的类创建对象
        let persono = Person()
        print(persono.name,persono.age ?? 22)
        
        //基于person类自定义的类
        //        let student = Student()
        //如果继承的属性没有赋值，那使用的就是继承的类中已经定义好的
        //        print(student.name,student.age ?? 22,student.num)
        
        //调用重载方法
        let per = Person(name: "zhagnsan", age: 22)
        print(per.name, per.age ?? 22)
        
        let stu = Student(num: 33, name: "nihao", age: 22)
        print(stu.name, stu.age, stu.num)
        
    }
    
    //闭包
    func closure(){
        //注意，只有闭包和懒加载有等号
        let closuer = {(result:String) -> Void in
            print(result)
        }
        
        //执行函数 1
        loadData(type: "swift", callback: closuer)
        // 执行函数 2
        //  尾随闭包
        //  闭包作为函数的最后一个参数传递, 小括号提前关闭, 闭包写在小括号外面 ->  尾随闭包
        //注意：是闭包作为函数的最后一个参数
        //相当于在{ }中又重新定义了一遍闭包
        loadData(type: "swift"){(result:String) -> Void in
            print(result)
        }
        
        //如果函数只有一个参数,并且是闭包,那么小阔号还可以省略, 闭包写在函数外面
        loadData1(){(result) in
            print(result)
        }
        //小括号还可以省略
        loadData1{(result) in
            print(result)
        }
    }
    
    //将闭包作为唯一的参数，传递到函数中
    func loadData1(callback: @escaping (String) -> ()){
        DispatchQueue.global().async {
            Thread.sleep(forTimeInterval: 1)
            let result = "hello"
            DispatchQueue.main.async {
                callback(result)
            }
        }
    }
    
    //将闭包作为参数传到函数中
    //@escaping -> 逃逸, 表示这个闭包不在当前函数作用域中执行
    //闭包逃逸 ！！！
    //@escaping () 中传递闭包参数的类型和返回值的类型
    func loadData(type:String,callback: @escaping (String) -> ()){
        // 全局 异步
        DispatchQueue.global().async {
            Thread.sleep(forTimeInterval: 1)
            let result = "hello"
            DispatchQueue.main.async {
                //执行闭包
                //定义的闭包是带参数的
                callback(result)
            }
        }
    }
    
    //  闭包格式
    /**
     1. 闭包与oc里面的block很类似
     2. 是一个预习定义好的代码块 -> '{代码}'
     3. 可以作为函数参数使用, 可以返回值使用
     4. 在需要的时候去执行 blockName(xx), 闭包名(xx)
     5. 闭包里面如果使用self, 需要注意循环引用
     
     let closre = { (参数名: 参数类型, ..) -> 返回值类型 in
     
     //
     执行代码
     }
     
     */
    //有参数有返回值的闭包
    func demo11(){
        let closuer = {(a:Int,b:Int) -> Int in
                return a + b
        }
        let result = closuer(1,2)
        print(result)
    }
    //无参数无返回值的闭包
    func demo10(){
        let closure = { () in
            print("这是个闭包")
        }
        let closure1 = { () -> () in
            print("这也是个闭包")
        }
        let closure2 = { () -> Void in
            print("这还是个闭包")
        }
        
        //注意，闭包是需要进行调用的 闭包的调用形式与block类型
        closure()
        closure1()
        closure2()
    }
    

    //函数
    //嵌套函数
    func text4(){
        func text5(){
            print("HHEHH")
        }
        text5()
    }
    
    //无参数无返回值的三种形式
//    func text(){
//        print("HH")
//    }
    //or
//    func text() -> (){
//        print("HH")
//    }
    //or
    func text3() -> Void {
        print("HH")
    }
    
    //有参数有返回值
    // a  b  表示外部参数, 给调用方描述每个参数是什么意思
    func text2(a:Int,b:Int) -> Int {
        //  函数内部不能使用外部参数,外部参数是给调用方用的
        return a + b
    }
    
    //没参数没有返回值
    func text1(){
       print("rinima!")
    }
    //集合
    func demo8(){
        //不可变数组
//        let arr = [1,2,3]
        //不可变指定类型的数组
//        let arr:[Int] = [1,2,3]
//        print(arr)
        //可变数组
//        var arr = [1,2,3]
//        //可变数组 添加元素
//        arr.append(6)
//        print(arr)
        
        //指定string类型的可变数组
//        var strArr:[String] = [String]()
//        strArr.append("hello")
//        print(strArr)
        
        //数组的遍历
//        let array:[String] = ["he0","he1","he2"]
//        for i in 0..<array.count {
//            print(array[i])
//        }
//        for i in 0...(array.count - 1) {
//            print(array[i])
//        }
        
//        for i in array {
//            print(i)
//        }
//        for value in array {
//            print(value)
//        }
        //复杂写法  enumerated()
//        for(i,value) in array.enumerated(){
//            print("i:\(i),value:\(value)")
//        }
        
        //数组的合并
//        let arr1 = [1,2,3]
//        let arr2 = [4,5,6]
//        print(arr1 + arr2)
        //通过 += 对于可变数组添加元素
//        var arr = ["he","llo"]
//        arr += ["hehe"]
//        print(arr)
        
        //创建空的可变数组
//        var arr:[Int] = [Int]()
//        print(arr.count)
        
        //扩展方法
        /**
          contentsOf:   将["lele","heh","lsl"]作为一个整体，添加到可变数组中
         */
//        arr.insert(contentsOf:["lele","heh","lsl"], at: 1)
//        print(arr)

        
        //数组删除
//        var array:[Int] = [1,2,3]
//        array.append(2)
//        print(array)
//        array.remove(at: 2)
//        print(array)
        
        //可变数组中可以通过下标获得数据并可以修改
//        array[2] = 3
//        print(array)
        
        //字典的定义
        //不可变字典
        var dic: [String :Any] =  ["name":"sony","age":28]
        print(dic)
        
        //可变字典
//        var dic: [String : Any] = ["name":"sony","age":28]
//        print(dic)
        //可以修改键值对
//        dic["name"] = "jhon"
//        print(dic)
        
        //可以创建空的字典
//        var dic:[String:Any] = [String:Any]()
//        print(dic)
        
        //遍历字典
//        for (key,value) in dic{
//            print("key:\(key)","value:\(value)")
//        }
        
        //打印所有的key
//        for key in dic.keys{
//            print(key)
//        }
        //打印所有的value
//        for value in dic.values {
//            print(value)
//        }
        //判断字典是不是空的
//        if dic.isEmpty{
//            print("HH")
//        }else{
//            print("123")
//        }
//        if dic.count == 0{
//            print("HH")
//        }else{
//            print("123")
//        }
        
        
        
        //字典合并
        let dic1:[String : Any] = ["name":"sony","age":13]
        var dic2:[String : Any] = ["name":"jhon","age":19]
        
        for (key,value) in dic1{
            //合并
            dic2.updateValue(value, forKey: key)
            //或者
//            dic2[key] = value
        }
        
        //添加键值对，添加没有的键值对
        //根据key在字典里面是否存在,完成添加键值对或者修改键值对的操作
        dic2.updateValue("98", forKey: "scroe")
        
        //移除键值对
        dic2.removeValue(forKey: "age")
        
        //可变字典移除所有键值对
        dic2.removeAll()
        
        print(dic2)
    }
    
    //字符串
    /**
     //  swift 字符串使用 String 关键字, 它是一个结构体 , 量级别NSString要轻, 性能比NSString要高, 官方推荐使用
      //  oc 字符串使用NSString , 继承NSObject ,它是一个对象
      
      //  String类型的字符串可用直接支持遍历,NSString不可以
     */
    func demo7(){
        //遍历
//        let str: String = "hello"
//        for s in str{
//            print(s)
//        }
        //获取字符串长度
//        let str = "hello"
//        let count = str.count
//        let str1: String = "hello"
        //通过length 也可以获得长度
//        let length = (str1 as NSString).length
//        print(length)
//        print(count)
//        print(str.count)
        ////  在指定编码格式下统计字节的个数 -> 一个汉字对应是三个字节
//        let str = "hello你好"
//        let count = str.utf8.count
//        let count = str.lengthOfBytes(using: String.Encoding.utf8)
//        print(count)
        
        //定义字符串
        /**
         通过字面量定义字符串
         好比oc里面 不可变的字符串
         */
//        let str = "hello"
        
        /**
         好比oc里面 可变的字符串
         */
//        var str1 = "nihao"
//        str1 = "hi"
//        var str2:String = "nihaoya"
//        str2 = "ho"
//        print(str1,str2)
        
        //空字符串
//        var str = ""
//        var str1: String = String()
//        print(str,str1)
        //字符串的拼接
//        let str = "nihao"
//        let str1 = "hhhh"
//        print(str + str1)
//        var str2 = "fffff"
        //拼接 定义的就是可变字符串
//        str2 += str1
//        print(str2)

//        let y = 2021
        //将整型 转化为 string
//        str2 += String(y)
//        print(str2)
//        let year: Int? = 2021
//        let year: Int = 2021
//
//        let result = str2 + "\(year)"
//        print(result)
        //字符串格式化
//        let n = 2021
//        let y = 1
//        let r = 7
//        print("\(n):\(y):\(r)")
//        let result = String(format: "%02d:%02d:%02d", n,y,r)
//        let result = String(format: "%02d:%02d:%02d", arguments:[n,y,r])
//        print(result)
        
        //字符串截取
        let str: String = "hello"
        /**
        传入一个Range 区间进行截取 不行
        let str1 = str[..<2]
         */
        /**
         dropFirst(1) 从哪位开始截取
         prefix(1) 截取几位
         */
//        let str1 = str.dropFirst(1).prefix(1)
//        let str2 = str.dropFirst(2) //没有指定截取多少位，就从指定的位置开始到字符串末尾
        
        /**
        注意，由于drop方法得到的字符串是substring类型，所以需要转化一下，使用String(str.dropFirst(1))转化为String即可
         */
//        print(str1)
//        let str3:String = String(str.dropFirst(2))
//        print(str2)
        /**
         suffix(3)从最后一位倒数三位
         */
        let str4 = str.suffix(3)
        print(str4)
        
    }
    
    
    //循环
    func demo6(){
        /**
             for , for in , do-while , while
          */
        //   0 ..< 5  表示一个范围, 好比数学里面区间 [0,5) 取值范围 0-4
//        for i in 0 ..< 5{
//            print("hh")
//        }
        //   0 ... 5  表示一个范围 好比数学里面闭区间 [0,5] 取值范围 0-5
//       for i in 0 ... 5 {
//            print("HH  \(i)")
//        }
        
       var index = 0
        while index < 4 {
            index += 1
            print(index)
        }
        
        //  在swift 2.0 把do-while 改成 repeat - while
        repeat{
            index -= 1
            print(index)
        }while index > 0
        
        
    }
    //控制流 2
    @objc func demo5(){
//        let name: String? = "money"
//        let age: Int? = 20
//
//        if let n = name,var a = age{
//            // let a = age 是常量
//            a = 33 //var 变量可以修改值
//            print(n,a)
//        }
        
        /**
         多个条件判断 + 可绑类型
         */
//        let url: URL? = URL(string: "http://www.baidu.com")
        // url 不为nil 需要解包
//        if url != nil{
//            if url!.host == "www.baidu.com"{
//                print("cao")
//            }
//        }
        
        //可绑类型
        //不需要解包
//        if let u = url{
//            if u.host == "www.baidu.com" {
//                print("cao")
//            }
//        }
        
        //多个条件判断,前半部分是可绑类型 不需要解包
//        if let u = url, u.host == "www.baidu.com"{
//            print("cao")
//        }
//        let name: String? = "Sani"
//        let age: Int? = 26
//
//        if let n = name,let a = age, n == "Sani" && a == 26{
//            print("名字:\(n),年龄:\(a)")
//            /**
//             名字:Sani,年龄:26
//             */
//        }
        
         /**
               1. 省略break
               2. 可以判断任意数据类型
               3. 可以省略多括号
               4. 在case语句里面定义变量不需要加上大括号
               5. case 可以判断多个参数
               6. fallthrough case后面不能定义变量或者常量
               7. case 或者default 后面必须要跟上一条可执行的语句
               8. case 后面可以添加条件判断
            */
        
        //        let scoreStr = "一般"
        //        switch scoreStr {
        //        case "优":
        //            print("90-100")
        //            let a = 10
        //            print(a)
        //
        //        case "良", "一般":
        //            print("80-90")
        //            //  表示穿透
        //            fallthrough
        
        //        case "中":
        //            print("70-80")
        //        case "差":
        //            break
        ////            print("小于60")
        //        default:
        //            break
        ////            print("未知")
        //        }

    
    }
    //控制流 1
    @objc func demo3(){
        /**
         if语句的判断
         if 后面的小括号可以省略
         不能省略'{}'
         在swift里面没有非0即真的概念, if 逻辑判断必须是一个bool类型的值, 只有true/false -> 最终判断的是bool类型
         */
//     let num = 6
//        if num > 3{
//            print("hh")
//        }
        //可绑类型
//        let url: URL? = URL(string: "www.baidu.com")
//        if url != nil{
//            //强制解包
//            let urlRequest = URLRequest(url: url!)
//            print(urlRequest)
//        }else{
//            print("URL 非法")
//        }
        //可绑类型
//        if let u = url {
//            //将url 赋值给 常量u
//            let urlRequest = URLRequest(url: u)
//            print(urlRequest)
//        }else{
//            print("URL 非法")
//        }
        /**
         //  guard let
         //  与if let 语意相反 (if let 只有可选类型不为nil 才会执行, guard let 只有可选类型为nil 才会执行)
         //  与if let 相比 逻辑处理可以省略一层嵌套'{}'
         */
        let url: URL? =  URL(string: "www.baidu.com")
        guard let u = url else{
            //url是nil 之后就可以直接跳出
            print("URL 非法")
            return //URL是nil 直接返回
        }
        
        //。。。可以写逻辑
        //注意，此时的URL已经赋值给了  U 
        let urlRequest = URLRequest(url: u)
        print(urlRequest)
        
        
    }
    //可选类型 1
    @objc func demo2(){
        //可选类型  使用时一定要进行强制解包 只有是可选类型才能接收nil值
        let a: Int? = 20
//        let a:Int? = nil
        
        let b = 20
        
        //  '!' 表示强制解包
         //  fatal error: unexpectedly found nil while unwrapping an Optional value
         //  对应可选类型的值为nil进行强制解包报错
         //  使用! 的时候要向系统保证我的值一定存在,不能是nil
 
    //强制解包时 值不能为nil 此处的就是保证
        if a != nil{
            //使用！进行解包
           let result = a! + b
           print(result)
        }
        
        //
        if a != nil{
            let result = a! + b
            print(result)
        }
       
        //空合运算符 ？？
        //如果a的值时nil就赋一个值
        //使用空合运算符之后，不需要解包
        let result = (a ?? 10) + b
        print(result)
        
        //变量的可选类型
        var g: Int?
        print(g ?? nil) //输出的结果就是nil 对一个可选类型没有赋值，结果就是nil
        
        //变量的可选类型
        var h: Int?
        print(h ?? "11") //输出结果为11 如果h的值是nil 输出的结果就是11
        
        
        //注意：如果是常量的可选类型就不行了 常量需要初始化
        let f: Int? = nil
        print(f ?? "12")
        
    }
    //可选类型
    @objc func demo4(){
        /**
         Swift 的可选（Optional）类型，用于处理值缺失的情况。

         可选表示"那儿有一个值，并且它等于 x "或者"那儿没有值"。
         */
        
        //基本使用
//        var str: String? = nil
//        if str != nil{
//            print(str as Any)
//        }else{
//            print("str is nil")
//        }
        //或者
//        var strI: String? = nil
//        strI = "Hello it is swift"
//        if strI != nil{
//            print(strI as Any)
//        }else{
//            print("str is nil")
//        }
        //强制解析
//        var str: String? = nil
//        str = "hello is swift!"
//        if str != nil{
//            //强制解析
//            print(str!)
//        }else{
//            print("str is nil")
//        }
//        if str != nil{
//            print(str! ?? "str is nil")
//        }
        //自动解析
        /**
         在声明可选变量时使用感叹号（!）替换问号（?）。

         这样可选变量在使用时就不需要再加一个感叹号（!）来获取值，它会自动解析。
         */
//        var str: String!
//        str = "hello is Swift"
//        if str != nil{
//            print(str as Any)
//        }else{
//            print("str is nil")
//        }
//        if str != nil{
//            print(str ?? "str is nil")
//        }
        //可选绑定
        /**
         使用可选绑定（optional binding）来判断可选类型是否包含值，如果包含就把值赋给一个临时常量或者变量。

         可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。
         */
        var str: String? = nil
        str = "hello is Swift!"
        if let strI = str{
            print(strI)
        }else{
            print("str is nil");
        }
        
    }
    //常量 变量
    @objc func demo1(){
        //没有指定类型的常量与变量
        let a = 10  //常量  一经赋值不可改变
//        a = 20
        var b = 30  //变量  可以修改数据
        b = 40
        print(a,b)
        
        //指定类型的常量与变量
        let c: Double = 30.5
        let d: Int = 3
        
//        在swift里面没有隐式类型转换，不同类型的数据不能进行运算
        let result = Double(a) + c
        let result2 = a + d
        
        print(result)
        print(result2)
        
    }

    //函数1
    @objc func view1(){
        //视图
        let v = UIView (frame: CGRect(x: 200, y: 200, width: 100, height: 100))
        v.backgroundColor = UIColor.red
        //添加
        self.view.addSubview(v)
        

        //按钮
        //添加按钮的形式
        let button = UIButton(type: UIButton.ButtonType.contactAdd)
        button.frame = CGRect(x: 10, y: 10, width: 200, height: 200)
        button.backgroundColor = UIColor.blue //链接式编程
        //添加点击事件
        /**
         按钮的两种响应方式
         */
//        button.addTarget(self, action: #selector(text), for: UIControl.Event.touchUpInside)
        button.addTarget(self, action: #selector(text), for: .touchUpInside)
        self.view.addSubview(button)
    }
    
    //添加自定义方法时是需要添加 @objc
    @objc func text(){
        //
        print("HH")
    }
    
  
    
    
}

